package com.ng.framework.view.desktop;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class NGDualList<T> extends JPanel implements ActionListener, ListSelectionListener, ListDataListener {

	private static final long serialVersionUID = -1163960222737691487L;
	
	private JButton addAllButton;
	private JButton addSelectedButton;
	private JButton removeAllButton;
	private JButton removeSelectedButton;
	private NGList<T> leftList;
	private NGList<T> rightList;
	private Class<T> clazz;
	
	public NGDualList(Class<T> clazz) {
		this.clazz = clazz;
		
		this.buildGui();
		
		this.setOpaque(false);
	}

	private void buildGui() {
		this.setLayout(new GridBagLayout());
		
		JScrollPane leftListScrollPane = new JScrollPane(this.getLeftList(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		leftListScrollPane.getViewport().setPreferredSize(new Dimension(-1, -1));
		this.add(leftListScrollPane, new GridBagConstraints(0, 0, 1, 4, 0.5, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
		this.add(this.getAddSelectedButton(), new GridBagConstraints(1, 0, 1, 1, 0, 0.5, GridBagConstraints.SOUTH, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
		this.add(this.getAddAllButton(), new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
		this.add(this.getRemoveAllButton(), new GridBagConstraints(1, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
		this.add(this.getRemoveSelectedButton(), new GridBagConstraints(1, 3, 1, 1, 0, 0.5, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
		JScrollPane rightListScrollPane = new JScrollPane(this.getRightList(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		rightListScrollPane.getViewport().setPreferredSize(new Dimension(-1, -1));
		this.add(rightListScrollPane, new GridBagConstraints(2, 0, 1, 4, 0.5, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
	}
	
	private NGList<T> getLeftList() {
		if(leftList == null) {
			this.leftList = new NGList<T>(this.clazz);
			leftList.addListSelectionListener(this);
			leftList.getModel().addListDataListener(this);
		}
		return leftList;
	}
		
	private JButton getAddAllButton() {
		if(addAllButton == null) {
			this.addAllButton = NGGUIUtils.createIconButton("icons/control-double.png", this);
			addAllButton.setEnabled(false);
		}
		return addAllButton;
	}
	
	private JButton getAddSelectedButton() {
		if(addSelectedButton == null) {
			this.addSelectedButton = NGGUIUtils.createIconButton("icons/control.png", this);
			addSelectedButton.setEnabled(false);
		}
		return addSelectedButton;
	}
	
	private JButton getRemoveSelectedButton() {
		if(removeSelectedButton == null) {
			this.removeSelectedButton = NGGUIUtils.createIconButton("icons/control-180.png", this);
			removeSelectedButton.setEnabled(false);
		}
		return removeSelectedButton;
	}
	
	private JButton getRemoveAllButton() {
		if(removeAllButton == null) {
			this.removeAllButton = NGGUIUtils.createIconButton("icons/control-double-180.png", this);
			removeAllButton.setEnabled(false);
		}
		return removeAllButton;
	}
	
	private NGList<T> getRightList() {
		if(rightList == null) {
			this.rightList = new NGList<T>(this.clazz);
			rightList.addListSelectionListener(this);
			rightList.getModel().addListDataListener(this);
		}
		return rightList;
	}
	
	public void setLeftListElements(List<T> elements) {
		this.setLeftListElements(elements, true);
	}
	
	public void setLeftListElements(List<T> elements, boolean sort) {
		this.getLeftList().setElements(elements, sort);
	}
	
	public void setRightListElements(List<T> elements) {
		this.setRightListElements(elements, true);
	}
	
	public void setRightListElements(List<T> elements, boolean sort) {
		this.getRightList().setElements(elements, sort);
	}
	
	public List<T> getLeftListElements() {
		return this.getLeftList().getElements();
	}

	public List<T> getRightListElements() {
		return this.getRightList().getElements();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == this.getAddAllButton()) {
			this.getRightList().addElements(this.getLeftList().getElements());
			this.getLeftList().removeAllElements();
		} else if(e.getSource() == this.getAddSelectedButton()) {
			List<T> leftListSelectedElements = this.getLeftList().getSelectedElements();
			this.getRightList().addElements(leftListSelectedElements);
			this.getLeftList().removeElements(leftListSelectedElements);
		} else if(e.getSource() == this.getRemoveSelectedButton()) {
			List<T> rightListSelectedElements = this.getRightList().getSelectedElements();
			this.getLeftList().addElements(rightListSelectedElements);
			this.getRightList().removeElements(rightListSelectedElements);
		} else if(e.getSource() == this.getRemoveAllButton()) {
			this.getLeftList().addElements(this.getRightList().getElements());
			this.getRightList().removeAllElements();
		}
	}
	
	@Override
	public void valueChanged(ListSelectionEvent e) {
		if(!e.getValueIsAdjusting()) {
			if(e.getSource() == this.getLeftList() || e.getSource() == this.getRightList()) {
				this.getAddSelectedButton().setEnabled(getLeftList().getSelectedIndices().length > 0);
				this.getRemoveSelectedButton().setEnabled(getRightList().getSelectedIndices().length > 0);
			}
		}
		
	}

	@Override
	public void intervalAdded(ListDataEvent e) {
		if(e.getSource() == this.getLeftList().getModel()) {
			this.getAddAllButton().setEnabled(this.isEnabled());
		} else if(e.getSource() == this.getRightList().getModel()) {
			this.getRemoveAllButton().setEnabled(this.isEnabled());
		}
	}

	@Override
	public void intervalRemoved(ListDataEvent e) {
		if(e.getSource() == this.getLeftList().getModel()) {
			this.getAddAllButton().setEnabled(this.getLeftList().getElementCount() > 0);
		} else if(e.getSource() == this.getRightList().getModel()) {
			this.getRemoveAllButton().setEnabled(this.getRightList().getElementCount() > 0);
		}
	}

	@Override
	public void contentsChanged(ListDataEvent e) {}
	
	@Override
	public void setEnabled(boolean enabled) {
		super.setEnabled(enabled);
		
		this.getLeftList().setEnabled(enabled);
		this.getRightList().setEnabled(enabled);
		
		this.getAddSelectedButton().setEnabled(enabled && this.getLeftList().getSelectedIndex() > 0);
		this.getAddAllButton().setEnabled(enabled && this.getLeftList().getElementCount() > 0);
		this.getRemoveAllButton().setEnabled(enabled && this.getRightList().getElementCount() > 0);
		this.getRemoveSelectedButton().setEnabled(enabled && this.getRightList().getSelectedIndex() > 0);
	}
	
}
